import 'dart:async';
import 'dart:convert';

import 'package:dio/dio.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:rxdart/rxdart.dart';

import 'NWApi.dart';
import 'default.dart';

///http请求
class HttpManager {
  // static const CONTENT_TYPE = "application/json";

  static const CONTENT_TYPE = "application/x-www-form-urlencoded";

  static Dio? _dio;
  static final int CONNECR_TIME_OUT = 10000;
  static final int RECIVE_TIME_OUT = 10000;
  static Map<String, CancelToken> _cancelTokens = new Map<String, CancelToken>();

  HttpManager._internal() {
    initDio();
  }

  static HttpManager _httpManger = HttpManager._internal();

  factory HttpManager() {
    return _httpManger;
  }

  //get请求
  PublishSubject<Default<T>> get<T>(String url, {Map<String, dynamic>? queryParameters, bool isCancelable = true}) {
    return _requstHttp<T>(url, "get", queryParameters, isCancelable);
  }

  //post请求
  PublishSubject<Default<T>> post<T>(String url, {Map<String, dynamic>? queryParameters, bool isCancelable = true}) {
    return _requstHttp<T>(url, "post", queryParameters, isCancelable);
  }

  //post请求 上传文件
  PublishSubject<Default<T>> postUploadFile<T>(String url,
      {Map<String, dynamic>? queryParameters, bool isCancelable = true}) {
    return _requstHttp<T>(url, "postFile", FormData.fromMap(queryParameters), isCancelable);
  }

  //put请求
  PublishSubject<Default<T>> put<T>(String url, {Map<String, dynamic>? queryParameters, bool isCancelable = true}) {
    return _requstHttp<T>(url, "put", queryParameters, isCancelable);
  }

  //deletet请求
  PublishSubject<Default<T>> delete<T>(String url, {Map<String, dynamic>? queryParameters, bool isCancelable = true}) {
    return _requstHttp<T>(url, "delete", FormData.fromMap(queryParameters), isCancelable);
  }

  /// 参数说明  url 请求路径
  /// queryParamerers  是 请求参数
  /// isCancelable 是设置改请求是否能被取消
  PublishSubject<Default<T>> _requstHttp<T>(String url, [String? type, queryParameters, bool? isCancelable]) {
    Future future;
    PublishSubject<Default<T>> publishSubject = PublishSubject<Default<T>>();
    CancelToken? cancelToken;
    //保存取消token
    if (isCancelable!) {
      //如果需要取消网络请求，在这里标记cancelToken
      // cancelToken = _cancelTokens[g.Get.currentRoute] == null ? CancelToken() : _cancelTokens[g.Get.currentRoute];
      // _cancelTokens[g.Get.currentRoute] = cancelToken;
      // debugPrint("当前路由：${g.Get.currentRoute}");
    }
    if (type == "get") {
      future = _dio!.get(url, queryParameters: queryParameters, cancelToken: cancelToken);
    } else if (type == "put") {
      future = _dio!.put(url, data: queryParameters, cancelToken: cancelToken);
    } else if (type == "post" || type == "postFile") {
      future = _dio!.post(url, data: queryParameters, cancelToken: cancelToken);
    } else if (type == "delete") {
      future = _dio!.delete(url, data: queryParameters, cancelToken: cancelToken);
    } else {
      future = _dio!.patch(url, data: queryParameters, cancelToken: cancelToken);
    }
    if (type != "postFile") debugPrint("请求参数：${json.encode(queryParameters)}");
    debugPrint("请求地址：${NWApi.baseApi}$url  请求方式：$type");
    future.then((da) {
      Response data = da;
      // LogUtil.e(("请求地址：$url，返回数据：$data"));
      if (data.headers.value("code") == "401") {
        //token过期 提示并进入登录界面
        return;
      }
      //需要先过滤 error ， 根据和后台的 约定 ， 搞清楚什么是失败
      int code = json.decode(data.toString())["code"];
      if (code != 200) {
        debugPrint("请求错误${json.decode(data.toString())}");
        callError(
          publishSubject,
          MyError(code, json.decode(data.toString())["message"]),
        );
      } else {
        //解析
        // debugPrint(json.decode(data.toString()));
        publishSubject.add(Default<T>.fromJson(json.decode(data.toString())));
        publishSubject.close();
      }
    }).catchError((err) {
      debugPrint(err.toString());
      //接口抛出异常，根据不同得返回做对应得操作，最后统一返回MyError
      if (err.toString() != "DioError [DioErrorType.CANCEL]: ") {
        if (err is DioError) {
          var error = json.decode(err.response.toString());
          if (error == null) {
            callError(publishSubject, MyError(-1, "请求错误"));
          } else {
            if (error['code'] == 401) {
              return;
            }
            debugPrint("请求错误1：${error['message']} code:${error['code']}");
            callError(publishSubject, MyError(error['code'], error['message']));
          }
        } else {
          debugPrint("请求错误2：${err.toString()}");
          callError(publishSubject, MyError(1, err.toString()));
        }
      } else {
        debugPrint("这个网络请求的取消操作被拦截了");
      }
    });
    return publishSubject;
  }

  ///请求错误以后 做的一些事情
  void callError(PublishSubject publishSubject, MyError error) {
    publishSubject.addError(error);
    publishSubject.close();
  }

  ///取消请求
  static void cancelHttp(String tag) {
    debugPrint("$tag ${_cancelTokens.containsKey(tag)}");
    if (_cancelTokens.containsKey(tag)) {
      if (!_cancelTokens[tag]!.isCancelled) {
        _cancelTokens[tag]!.cancel();
      }
      _cancelTokens.remove(tag);
    }
  }

  ///配置dio
  void initDio() {
    _dio = Dio();
    //服务器地址
    _dio!.options.baseUrl = NWApi.baseApi;
    //请求超时的时间
    _dio!.options.connectTimeout = CONNECR_TIME_OUT;
    //接收超时的时间
    _dio!.options.receiveTimeout = RECIVE_TIME_OUT;
    _dio!.options.contentType = CONTENT_TYPE;

    /// 添加拦截器
    _dio!.interceptors.add(new MyIntercept());
  }
}

class MyError {
  int code;
  String message;

  MyError(this.code, this.message);
}

class MyIntercept extends Interceptor {
  @override
  onRequest(RequestOptions options) {
    // debugPrint("请求token：${SpConfig().getUserToken()}");
    //添加请求头数据
    options.headers.addAll({
      "token": "...",
    });
    return super.onRequest(options);
  }
}
